To be able to edit code and run cells, you need to run the notebook yourself. Where would you like to run the notebook?

This notebook takes about 40 seconds to run.

In the cloud (experimental)

Binder is a free, open source service that runs scientific notebooks in the cloud! It will take a while, usually 2-7 minutes to get a session.

On your computer

(Recommended if you want to store your changes.)

  1. Copy the notebook URL:
  2. Run Pluto

    (Also see: How to install Julia and Pluto)

  3. Paste URL in the Open box

Frontmatter

If you are publishing this notebook on the web, you can set the parameters below to provide HTML metadata. This is useful for search engines and social media.

Author 1

Including local JS modules

👀 Reading hidden code
177 μs

Sample ES6 project

Create a sample folder and populate it with some JS modules:

👀 Reading hidden code
228 μs
"/tmp/jl_yGFAHR"
👀 Reading hidden code
source_folder = begin
f = mktempdir()

write(joinpath(f, "index.js"), """
import { cool } from "./cool.js"
import { also_cool } from "./also/cool.js"
export const hello = (x) => [cool(x), also_cool(x)]
""")

write(joinpath(f, "cool.js"), """
// I can import from URLs, they will join the bundle:
import _ from "https://cdn.esm.sh/v58/lodash-es@4.17.21/es2021/lodash-es.js"
export let cool = x => _.repeat("hello ", x)
""")

mkdir(joinpath(f, "also" ))
write(joinpath(f, "also", "cool.js"), """
export let also_cool = (x) => " world!"
""")


f
end
356 μs
readdir(f)
👀 Reading hidden code
45.0 μs
"/tmp/jl_yGFAHR/index.js"
input_file = joinpath(source_folder, "index.js")
👀 Reading hidden code
15.3 μs

Bundle

Try changing the code in one of the JS files in the first section (above), and the bundler will automatically re-run!

👀 Reading hidden code
230 μs
import Deno_jll: deno
👀 Reading hidden code
644 ms
"var __global\$ = globalThis || (typeof window !== \"undefined\" ? window : self);\nvar wd = typeof __global\$ == \"object\" && __global\$ && __global\$.Object === Object && __global\$, Eo = wd;\nvar Ld = typeof self == \"object\" && self && self.Object === Object && self, Ed = Eo || Ld || Function(\"return thi" ⋯ 128737 bytes ⋯ "Of = i.prototype.value = Kr.value;\ni.prototype.first = i.prototype.head;\nRd && (i.prototype[Rd] = Kr.toIterator);\nvar PE = i;\nlet cool = (x)=>PE.repeat(\"hello \", x)\n;\nlet also_cool = (x)=>\" world!\"\n;\nconst hello1 = (x)=>[\n        cool(x),\n        also_cool(x)\n    ]\n;\nexport { hello1 as hello };\n\n"
bundle_code = begin
error_file = tempname()

try
read(pipeline(`$(deno()) bundle $(input_file)`, stderr=error_file), String)
catch e
if e isa ProcessFailedException
@htl("""
<h4>❌ Bundle failed</h4>
<pre><code>$(read(error_file, String))</code></pre>
""")
else
rethrow(e)
end
end
end
👀 Reading hidden code
636 ms

Use it inside code

👀 Reading hidden code
178 μs
@bind x Slider(1:1000)
👀 Reading hidden code
233 ms
hello world!
my_widget(x)
👀 Reading hidden code
Deprecated, use `AbstractPlutoDingetjes.Display.published_to_js(x)` instead of `PlutoRunner.publish_to_js(x)`.
319 ms
my_widget (generic function with 1 method)
function my_widget(x)
@htl("""
<script>
const { hello } = $(import_local_js(bundle_code))
let result = hello($(x))
return html`<span>\${result}</span>`
</script>
""")
end
👀 Reading hidden code
808 μs

Magic

We use publish_to_js to make the string available to JS running in the cell output. Inside the JS, we turn the string into a blob URL and call import() on that.

We create a Map, called window.created_imports, to keep track of strings that we already imported. When you re-import the same string a second time, the original import result is retured.

👀 Reading hidden code
361 μs
import_local_js (generic function with 1 method)
function import_local_js(code::AbstractString)

code_js =
try
Main.PlutoRunner.publish_to_js(code)
catch
repr(code)
end
HypertextLiteral.JavaScript(
"""
await (() => {
window.created_imports = window.created_imports ?? new Map()
let code = $(code_js)
if(created_imports.has(code)){
return created_imports.get(code)
} else {
let blob_promise = new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = async () => {
try {
resolve(await import(reader.result))
} catch(e) {
reject()
}
}
reader.onerror = () => reject()
reader.onabort = () => reject()
reader.readAsDataURL(
new Blob([code], {type : "text/javascript"}))
})
created_imports.set(code, blob_promise)
return blob_promise
}
})()
"""
)
end
👀 Reading hidden code
675 μs

Other attempts

👀 Reading hidden code
180 μs
"console.log(\"I should run only once!\")\n\nexport const x = 345\n"
code = """
console.log("I should run only once!")

export const x = 345
"""
👀 Reading hidden code
10.9 μs
using Base64
👀 Reading hidden code
204 μs
"data:text/javascript;base64,Y29uc29sZS5sb2coIkkgc2hvdWxkIHJ1biBvbmx5IG9uY2UhIikKCmV4cG9ydCBjb25zdCB4ID0gMzQ1Cg=="
base64url = "data:text/javascript;base64,$(base64encode(code))"
👀 Reading hidden code
29.9 ms
@htl("""



<script>

const { x } = await import($(base64url))


console.log(x)



</script>



""")
👀 Reading hidden code
7.0 ms
@htl("""
<script>

const {x} = $(import_local_js(code2))

console.log(x)

</script>
""")
👀 Reading hidden code
Deprecated, use `AbstractPlutoDingetjes.Display.published_to_js(x)` instead of `PlutoRunner.publish_to_js(x)`.
475 ms
"console.log(\"I should run only once!\")\n\nexport const x = 32\n"
code2 = """
console.log("I should run only once!")

export const x = 32
"""
👀 Reading hidden code
10.8 μs
using PlutoUI
👀 Reading hidden code
163 ms
@bind x2 Slider(1:1000)
👀 Reading hidden code
637 μs
1
@htl("""
<script>

const x = $(PlutoRunner.publish_to_js(x2))


return html`<span>\${x}</span>`

</script>

""")
👀 Reading hidden code
Deprecated, use `AbstractPlutoDingetjes.Display.published_to_js(x)` instead of `PlutoRunner.publish_to_js(x)`.
14.3 ms
using HypertextLiteral
👀 Reading hidden code
128 μs